#! -*- coding: utf-8 -*-
import re


class FancyDict(dict):

    def __getattr__(self, key):
        try:
            return self[key]
        except KeyError, k:
            raise AttributeError(k)

    def __setattr__(self, key, value):
        self[key] = value

    def __delattr__(self, key):
        try:
            del self[key]
        except KeyError, k:
            raise AttributeError(k)


class AppVersion(object):
    """
    App version
    """

    def __init__(self, ios=None, android=None, web=None, is_ios_ipad=False):
        assert (ios or android or web), "Must specified a version"
        self.ios = ios
        self.android = android
        self.web = web
        # If this is an ios ipad version
        self.is_ios_ipad = is_ios_ipad

    @property
    def is_ios(self):
        return bool(self.ios)

    @property
    def is_android(self):
        return bool(self.android)

    @property
    def is_app(self):
        return bool(self.android) or bool(self.ios)

    @property
    def is_web(self):
        return bool(self.web)

    def __cmp__(self, other):
        if isinstance(other, NoAppVersion):
            return 1
        for key in ('ios', 'android', 'web'):
            a = getattr(self, key)
            b = getattr(other, key) if isinstance(other, AppVersion) else other
            if a and b:
                if a > b:
                    return 1
                elif a == b:
                    return 0
                else:
                    return -1
        raise Exception('Invalid version given.')

    def __eq__(self, other):
        try:
            return self.__cmp__(other) == 0
        except Exception, e:
            print e
            return False

    def __ne__(self, other):
        return not (self == other)

    def __str__(self):
        ret = ['<AppVersion: ', ]
        if self.ios:
            ret.append('(IOS:%s)' % self.ios)
        if self.android:
            ret.append('(Android:%s)' % self.android)
        if self.web:
            ret.append('(WEB:%s)' % self.web)
        ret.append('>')
        return "".join(ret)

    def to_tags(self):
        tags = []
        if self.ios:
            tags.append('ios_%s' % self.ios)
        if self.android:
            tags.append('android_%s' % self.android)
        if self.web:
            tags.append('web_%s' % self.web)
        return tags

    @classmethod
    def from_tags(cls, tags):
        try:
            if not isinstance(tags, (list, tuple)):
                tags = [tags]
            kwargs = dict(tag.split('_', 1) for tag in tags)
            print kwargs
            return cls(**kwargs)
        except:
            return None


class NoAppVersion(object):
    """
    No appversion
    """
    is_ios = False
    is_ios_ipad = False
    is_android = False
    is_app = False
    is_web = False

    def __cmp__(self, other):
        if isinstance(other, NoAppVersion):
            return 0
        return -1

    def __str__(self):
        return "<NoAppVersion>"

    def __nonzero__(self):
        """be boolean False"""
        return False

    def __eq__(self, other):
        if isinstance(other, NoAppVersion):
            return True
        return False

    def __ne__(self, other):
        return not (self == other)

    def to_tags(self):
        return []


VERSION_RE = re.compile(r'^\d+\.\d+(\.\d+)?$')


def get_version_from_user_agent(user_agent):
    """
    Get AppVersion instance from a given user_agent string.

    Args:
    ~~~~~

    - user_agent: String

    Returns:
    ~~~~~~~~

    AppVersion instance or NoAppVersion instance

    """
    raw_user_agent = user_agent
    # Replace special versions
    user_agent = raw_user_agent.replace('/2.3.0.1/', '/2.3.0/')
    try:
        device = 'ios'
        r = re.compile('breadtrip\S*')
        user_agent = r.search(user_agent.lower()).group().strip()
        prefix, version, _version = user_agent.split('/', 2)
        if version.lower() == 'android':
            version = _version.split('/')[0]
            device = 'android'
        is_ios_ipad = 'ipad' in raw_user_agent.lower()
        if VERSION_RE.match(version):
            return AppVersion(**{device: version, 'is_ios_ipad': is_ios_ipad})
        return NoAppVersion()
    except:
        return NoAppVersion()
